package com.cn.damain.po;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.*;
import java.util.*;

public class AutoCreateEntity {

    @Value("${spring.datasource.driver-class-name}")
    public String driver;
    @Value("${spring.datasource.url}")
    public String url;
    @Value("${spring.datasource.username}")
    public String username;
    @Value("${spring.datasource.password}")
    public String password;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     *
     * @param dataBaseName 数据库名
     * @param tableNameList 表名集合  当集合为空时，根据数据库获取所有表名
     * @param packageName 包名
     * @param isAddEntitySuffix 类名是否添加Entity后缀 true-添加 false-不添加
     * @param isUseLomBok 是否使用@Data注解 true-是 false-否
     */
    public void createEntity(String dataBaseName, List<String> tableNameList, String packageName, boolean isAddEntitySuffix, boolean isUseLomBok) throws SQLException, ClassNotFoundException {
        if (CollectionUtils.isEmpty(tableNameList)) {
            // 当表名集合为空时  获取所有表名
            List<String> tableNames = getTableNameList();
            tableNameList = new ArrayList<>();
            tableNameList.addAll(tableNames);
        }
        for (String tableName : tableNameList) {
            if (null == tableName) continue;
            // 将表名改为驼峰 首字母大写
            String className=toCamelCase(tableName,true)+(isAddEntitySuffix?"Entity":"");
            StringBuffer classBuffer=new StringBuffer();
            List<Map<String, String>> filedMaps = getFiledMaps(dataBaseName, tableName,classBuffer);
            classBuffer.append("import java.lang.*;\r\n");
            classBuffer.append("import java.math.*;\r\n");
            classBuffer.append("import java.sql.*;\r\n");
            if (isUseLomBok) {
                classBuffer.append("import lombok.Data;\r\n\r\n\r\n");
                classBuffer.append("@Data\r\n");
                classBuffer.append("@EqualsAndHashCode(callSuper = false)\n" +
                        "@Accessors(chain = true)\r\n");
                classBuffer.append("@TableName(\"" + tableName + "\")\r\n");
            }
            classBuffer.append("public class " + className + " {\r\n\r\n");
            processAllAttrs(classBuffer,filedMaps);
            // 写入set get方法
            if (!isUseLomBok) {
                writeSetGetMethod(classBuffer, filedMaps);
            }
            classBuffer.append("}\r\n");

            // 创建实体类文件
            markerBean(className,classBuffer.toString(),packageName);
        }
    }

    /**
     * 获取所有表名
     */
    public List<String> getTableNameList() throws SQLException, ClassNotFoundException {

        List<String> tableNameList = new LinkedList<>();
        //加载驱动
        Class.forName(driver);
        //获得数据库连接
        Connection connection = DriverManager.getConnection(url, username, password);
        //获得元数据
        DatabaseMetaData metaData = connection.getMetaData();
        //获得表信息
        ResultSet tables = metaData.getTables(connection.getCatalog(), null, "%", new String[]{"TABLE"});

        while (tables.next()) {
            //获得表名
            String tableName = tables.getString("TABLE_NAME");
            tableNameList.add(tableName);
        }
        return tableNameList;
    }

    /**
     * 下划线改为驼峰
     * @param name 转换的内容
     * @param isFirstUpper  第一个字母是否需要转换为大写 true-是 false-否
     * @return
     */
    public String toCamelCase(String name, boolean isFirstUpper) {
        if (name == null) {
            return null;
        }
//        name = name.toLowerCase();
        StringBuilder sb = new StringBuilder(name.length());
        boolean upperCase = isFirstUpper;
        for (int i = 0; i < name.length(); i++) {
            char k = name.charAt(i);

            if ('_' == k) {
                upperCase = true;
            } else if (upperCase) {
                sb.append(Character.toUpperCase(k));
                upperCase = false;
            } else {
                sb.append(k);
            }
        }
        return sb.toString();
    }

    public void writeSetGetMethod(StringBuffer classBuffer, List<Map<String, String>> filedMaps) {
        for (int i = 0; i < filedMaps.size(); i++) {
            Map map = filedMaps.get(i);
            String fieldType = String.valueOf(map.get("fieldType"));
            String fieldName = String.valueOf(map.get("fieldName"));
            String name = toCamelCase(fieldName, true);
            classBuffer.append("\tpublic void set" + name + "("+ fieldType +" "+ fieldName+") {\r\n\r\n");
            classBuffer.append("\t\t this."+ fieldName + " = " + fieldName + ";\r\n\r\n");
            classBuffer.append("\t } \r\n\r\n");

            classBuffer.append("\tpublic " + fieldType + " get" + name + "() {\r\n\r\n");
            classBuffer.append("\t\t return "+ fieldName + ";\r\n\r\n");
            classBuffer.append("\t } \r\n\r\n");
        }
    }

    /**
     * 创建实体类文件
     * @param className 类名
     * @param content 添加的内容(字段注释等)
     * @param packageName 包名(com.xxx.xxx.xxx)
     */
    public void markerBean(String className, String content, String packageName) {
        String folder = System.getProperty("user.dir") + "/src/main/java/" + packageName.replace(".","/") + "/";
        File file = new File(folder);
        if (!file.exists()) {
            file.mkdirs();
        }
        String fileName = folder + className + ".java";
        try {
            File newjava = new File(fileName);
            FileWriter fw = new FileWriter(newjava);
            fw.write("package\t" + packageName + ";\r\n");
            fw.write(content);
            fw.flush();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析输出属性
     *
     * @return
     */
    private void processAllAttrs(StringBuffer sb,List<Map<String, String>> filedMaps) {
        for (int i = 0; i < filedMaps.size(); i++) {
            Map map = filedMaps.get(i);
            String fieldType = String.valueOf(map.get("fieldType"));
            String fieldName = String.valueOf(map.get("fieldName"));
            String fieldComment = String.valueOf(map.get("fieldComment"));
            if(!StringUtils.isEmpty(fieldComment)) {
                sb.append("\t/**\r\n").append("\t* ").append(fieldComment).append("\n").append("\t*/\r\n");
            }
            sb.append("\tprivate " + fieldType + " " + fieldName + ";\r\n\r\n");
        }
    }

    /**
     * 获取表字段信息(列名、类型、注释)
     * @param dataBaseName
     * @param tableName
     * @return
     */
    private List<Map<String, String>> getFiledMaps(String dataBaseName,String tableName,StringBuffer classBuffer) {
        String sql="SELECT * FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA ='"+dataBaseName+"' AND TABLE_NAME = '"+tableName+"'";
        List<Map<String, String>> tableFieldList = jdbcTemplate.query(sql, new RowMapper<Map<String, String>>() {
            @Override
            public Map<String,String> mapRow(ResultSet resultSet, int rowNum) throws SQLException {
                Map<String,String> fieldMap = new HashMap();
                String columnName = resultSet.getString("COLUMN_NAME");
                fieldMap.put("fieldName",toCamelCase(columnName,false));
                String dataType = resultSet.getString("DATA_TYPE");
                setFieldType(dataType.toUpperCase(),fieldMap,classBuffer);
                fieldMap.put("fieldComment",resultSet.getString("COLUMN_COMMENT"));
                return fieldMap;
            }
        });
        return tableFieldList;
    }

    /**
     *
     * @param columnType 字段类型
     * @param fieldMap
     * @param classBuffer
     */
    private void setFieldType(String columnType, Map<String,String> fieldMap,StringBuffer classBuffer) {

        String fieldType = "String";
        if (columnType.equals("INT") || columnType.equals("INTEGER") || columnType.equals("TINYINT")) {
            fieldType = "Integer";
        } else if(columnType.equals("BIGINT")) {
            fieldType = "Long";
        } else if(columnType.equals("DATETIME") || columnType.equals("DATE")) {
            classBuffer.append("import java.util.Date;\r\n");
            fieldType = "Date";
        } else if(columnType.equals("DOUBLE")) {
            fieldType = "Double";
        } else if(columnType.equals("BIT")) {
            fieldType = "Boolean";
        } else if(columnType.equals("FLOAT")) {
            fieldType = "Float";
        } else if(columnType.equals("DECIMAL")) {
            fieldType = "BigDecimal";
        } else if(columnType.equals("TIMESTAMP")) {
            classBuffer.append("import com.alibaba.fastjson.JSONObject;\r\n");
            fieldType = "LocalDateTime";
        } else if(columnType.equals("CHAR")) {
            fieldType = "Char";
        } else if(columnType.equals("JSON")) {
            fieldType = "JSONObject";
        }
        fieldMap.put("fieldType",fieldType);
    }
}
